﻿#include "guild_members_logic.h"

#include <algorithm>

#include "GuildMember_struct.h"
#include "GuildModuleMembers_struct.h"

#include "error/make_error_code.h"
#include "fwd.h"
#include "guild/guild_dump.hpp"
#include "guild/module/guild_module_loader.hpp"
#include "guild_service_basic.h"
#include "guildservicebasic.enum.h"
#include "logic/guild_basic_logic.h"
#include "redis/service_redis_fwd.hpp"


namespace guild_service {

bool GuildMembersLogic::GetModuleMembers(const guild_id_type guild_id,
                                        GuildModuleMembers& module_members) {
  return detail::GetGuildModule<GuildModuleMembers>(
      kGuildServiceBasicName, guild_id, kGuildModuleMembersName, module_members);
}

bool GuildMembersLogic::GetGuildMember(const role_uuid_type role_uuid,
                             GuildMember &member) {
  guild_id_type guild_id =
      GuildServiceBasicSingleton->GetGuildIdByRole(role_uuid);
  if (guild_id == kInvalidGuildId) {
    return false;
  }
  GuildModuleMembers module_members;
  if (!GuildMembersLogic::GetModuleMembers(guild_id, module_members)) {
    return false;
  }
  for (const auto &it: module_members.members) {
    if (it.role_uuid == role_uuid) {
      member = it;
      return true;
    }
  }
  return true;             
}

bool GuildMembersLogic::KickOutGuildMember(const role_uuid_type role_uuid,
                                           const role_uuid_type kick_role_uuid,
                                           error_code& ec) {
  if (role_uuid == kInvalidGuildId || kick_role_uuid == kInvalidGuildId) {
    ec = ErrorCode::ERR_INVALID_ROLE_UUID;
    return false;
  }

  std::vector<duty_type> duty_list{duty_type::GUILD_DUTY_CHAIRMAN,
                                   duty_type::GUILD_DUTY_VICE_CHAIRMAN};
  if (!GuildMembersLogic::CheckMemberDuty(role_uuid, duty_list)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_NO_PERMISSION;
    return false;
  }
  if (GuildMembersLogic::CheckMemberDuty(kick_role_uuid,
                                         duty_type::GUILD_DUTY_CHAIRMAN)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_NO_PERMISSION;
    return false;
  }

  guild_id_type guild_id =
      GuildServiceBasicSingleton->GetGuildIdByRole(role_uuid);
  if (guild_id == kInvalidGuildId) {
    ec = ErrorCode::ERR_GUILD_NOT_EXIST;
    return false;
  }

  GuildModuleMembers module_members;
  if (!GuildMembersLogic::GetModuleMembers(guild_id, module_members)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_LOAD_FAILED;
    return false;
  }

  auto& members = module_members.members;
  {
    auto iter =
        std::find_if(members.begin(), members.end(),
                     [kick_role_uuid](const GuildMember& member) -> bool {
                       return member.role_uuid == kick_role_uuid;
                     });
    if (iter != members.end()) {
      members.erase(iter);
    } else {
      ec = ErrorCode::ERR_GUILD_MEMBERS_ROLE_NOT_EXIST;
      return false;
    }
  }

  if (!detail::SaveGuildModule<GuildModuleMembers>(
          kGuildServiceBasicName, module_members, guild_id, kGuildModuleMembersName)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_SAVE_FAILED;
    return false;
  }

  return true;
}

bool GuildMembersLogic::QuitMember(const role_uuid_type role_uuid,
                                   guild_id_type& guild_id,
                                   uint32_t& member_left_count,
                                   error_code& ec) {
  guild_id = kInvalidGuildId;
  member_left_count = 0;

  if (role_uuid == kInvalidRoleUuid) {
    ec = ErrorCode::ERR_INVALID_ROLE_UUID;
    return false;
  }

  if (GuildMembersLogic::CheckMemberDuty(role_uuid,
                                         duty_type::GUILD_DUTY_CHAIRMAN)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_DUTY_CHAIRMAN;
    return false;
  }

  guild_id =
      GuildServiceBasicSingleton->GetGuildIdByRole(role_uuid);
  if (guild_id == kInvalidGuildId) {
    ec = ErrorCode::ERR_GUILD_NOT_EXIST;
    return false;
  }

  GuildModuleMembers module_members;
  if (!GuildMembersLogic::GetModuleMembers(guild_id, module_members)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_LOAD_FAILED;
    return false;
  }

  auto& members = module_members.members;

  // TODO 转交会长
  {
    auto iter = std::find_if(members.begin(), members.end(),
                             [role_uuid](const GuildMember& member) -> bool {
                               return member.role_uuid == role_uuid;
                             });
    if (iter != members.end()) {
      members.erase(iter);
    }
  }

  member_left_count = static_cast<uint32_t>(members.size());

  if (!GuildMembersLogic::RemoveGuildRole(guild_id, role_uuid)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_DEL_ID_FAILED;
    // LOG_DEBUG("删除公会角色唯一id失败 角色唯一id:%llu 公会id:%llu",
    // role_uuid, guild_id);
    return false;
  }

  if (member_left_count > 0) {
    if (!detail::SaveGuildModule<GuildModuleMembers>(kGuildServiceBasicName,
                                               module_members, guild_id,
                                               kGuildModuleMembersName)) {
      // LOG_DEBUG("保存公会成员失败 角色唯一id:%llu 公会id:%llu", role_uuid,
      // guild_id);
      ec = ErrorCode::ERR_GUILD_MEMBERS_SAVE_FAILED;
      return false;
    }
  }

  if (!GuildServiceBasic::SaveGuildRoleToRedis(kRedisDelOp, role_uuid,
                                               guild_id)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_DEL_ID_FAILED;
    // LOG_DEBUG("保存删除公会角色唯一id失败 角色唯一id:%llu 公会id:%llu",
    // role_uuid, guild_id);
    return false;
  }

  return true;
}

bool GuildMembersLogic::RemoveGuildRole(const guild_id_type guild_id,
                                        const role_uuid_type role_uuid) {
  return GuildServiceBasicSingleton->RemoveGuildRole(guild_id, role_uuid);
}

const GuildMembersLogic::duty_type GuildMembersLogic::GetMemberDuty(
    const role_uuid_type role_uuid) {
  GuildMember member;
  if (!GuildMembersLogic::GetGuildMember(role_uuid, member)) {
    return duty_type::GUILD_DUTY_NONE;
  }
  return member.duty;
}

bool GuildMembersLogic::CheckMemberDuty(const role_uuid_type role_uuid,
                                        const duty_type duty) {
  GuildMember member;
  if (!GuildMembersLogic::GetGuildMember(role_uuid, member)) {
    return false;
  }
  return member.duty == duty;
}

bool GuildMembersLogic::IsMemberDutyFull(const guild_id_type guild_id,
                                         const duty_type duty) {
  GuildModuleMembers module_members;
  if (!GuildMembersLogic::GetModuleMembers(guild_id, module_members)) {
    return true;
  }

  return GuildMembersLogic::IsMemberDutyFull(module_members, duty);
}

bool GuildMembersLogic::IsMemberDutyFull(const GuildModuleMembers module_members,
                               const duty_type duty) {
  // TODO CSV
  uint32_t max_count = 3;

  for (const auto& it : module_members.members) {
    if (it.duty == duty && --max_count == 0) {
      return true;
    }
  }

  return false;
}

bool GuildMembersLogic::SetMemberDuty(const role_uuid_type role_uuid,
                                      const role_uuid_type member_role_uuid,
                                      const duty_type duty, error_code& ec) {
  if (role_uuid == kInvalidRoleUuid
    || member_role_uuid== kInvalidRoleUuid) {
    ec = ErrorCode::ERR_INVALID_ROLE_UUID;
    return false;
  }
  if (duty == duty_type::GUILD_DUTY_NONE) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_INVALID_DUTY;
    return false;
  }
  if (!GuildServiceBasicSingleton->InSameGuild(role_uuid, member_role_uuid)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_ROLE_NOT_IN_SAME_GUILD;
    return false;
  }
  guild_id_type guild_id = GuildServiceBasicSingleton->GetGuildIdByRole(role_uuid);
  if (guild_id == kInvalidGuildId) {
    ec = ErrorCode::ERR_INVALID_GUILD_ID;
    return false;
  }
  
  GuildModuleMembers module_members;
  if (!GuildMembersLogic::GetModuleMembers(guild_id, module_members)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_LOAD_FAILED;
    return false;
  }

  if (GuildMembersLogic::IsMemberDutyFull(module_members, duty)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_DUTY_FULL;
    return false;
  }
  {
    GuildMember member;
    if (!GuildMembersLogic::GetGuildMember(role_uuid, member)) {
      ec = ErrorCode::ERR_GUILD_MEMBERS_ROLE_NOT_EXIST;
      return false;
    }
    member.duty = duty;
  }

  if (!detail::SaveGuildModule<GuildModuleMembers>(kGuildServiceBasicName,
                                             module_members, guild_id,
                                             kGuildModuleMembersName)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_SAVE_FAILED;
    // LOG_WARN("保存公会角色失败 角色唯一id:%llu 公会:%s", role_uuid,
    // DumpGuild(*guild_ptr).c_str());
    return false;
  }

  return true;
}


bool GuildMembersLogic::CheckMemberDuty(const role_uuid_type role_uuid,
                                        std::vector<duty_type>& duty_list) {
  if (duty_list.empty()) {
    return false;
  }

  GuildMember member;
  if (!GuildMembersLogic::GetGuildMember(role_uuid, member)) {
    return false;
  }

  for (const auto& it : duty_list) {
    if (member.duty == it) {
      return true;
    }
  }

  return false;
}

// GuildMember* GuildMembersLogic::GetMember(
//     const role_uuid_type role_uuid, const GetModulePriority priority/* =
//           GetModulePriority::GET_MODULE_PRI_USE_CACHE*/) {
//   if (role_uuid == kInvalidRoleUuid) {
//     return nullptr;
//   }
//   const Guild* guild_ptr =
//       GuildServiceBasicSingleton->GetGuildByRole(role_uuid);
//   if (!guild_ptr) {
//     return nullptr;
//   }

//   auto* members_ptr = GuildMembersLogic::GetMembers(*guild_ptr, priority);
//   if (!members_ptr) {
//     return nullptr;
//   }

//   for (auto& it : members_ptr->members) {
//     if (it.role_uuid == role_uuid) {
//       return &(it);
//     }
//   }

//   return nullptr;
// }

// GuildModuleMembers* GuildMembersLogic::GetMembers(
//     const Guild& guild,
//     const GetModulePriority
//         priority /* = GetModulePriority::GET_MODULE_PRI_USE_CACHE*/) {
//   return detail::GetGuildModule<GuildModuleMembers>(kGuildServiceBasicName, guild,
//                                               kGuildModuleMembersName, priority);
// }

// GuildModuleMembers* GuildMembersLogic::GetMembers(
//     const guild_id_type guild_id,
//     const GetModulePriority
//         priority /* = GetModulePriority::GET_MODULE_PRI_USE_CACHE*/) {
//   const Guild* guild_ptr = GuildServiceBasicSingleton->GetGuild(guild_id);
//   if (!guild_ptr) {
//     return nullptr;
//   }
//   return GuildMembersLogic::GetMembers(*guild_ptr, priority);
// }

std::size_t GuildMembersLogic::GetMembersCount(const guild_id_type guild_id) {
  GuildModuleMembers module_members;
  if (!GuildMembersLogic::GetModuleMembers(guild_id, module_members)) {
    return 0;
  }

  return module_members.members.size();
}

std::size_t GuildMembersLogic::GetMembersCountOnline(const guild_id_type guild_id) {
  // TODO
  return GuildMembersLogic::GetMembersCount(guild_id);
}

bool GuildMembersLogic::IsMemberFull(const guild_id_type guild_id) {
  GuildModuleMembers module_members;
  if (!GuildMembersLogic::GetModuleMembers(guild_id, module_members)) {
    return true;
  }
  return module_members.members.size() >= kMaxGuildMemberSize;
}

bool GuildMembersLogic::IsMemberExist(const guild_id_type guild_id,
                                      const role_uuid_type role_uuid) {
  GuildModuleMembers module_members;
  if (!GuildMembersLogic::GetModuleMembers(guild_id, module_members)) {
    return true;
  }

  for (const auto& it : module_members.members) {
    if (it.role_uuid == role_uuid) {
      return true;
    }
  }

  return false;
}

void GuildMembersLogic::ForeachMember(
    const guild_id_type guild_id,
    const GuildMembersLogic::ForeachMemberCallbackType& callback) {
  if (!callback) {
    return;
  }

  GuildModuleMembers module_members;
  if (!GuildMembersLogic::GetModuleMembers(guild_id, module_members)) {
    return;
  }

  for (const auto it : module_members.members) {
    callback(it);
  }
}

bool GuildMembersLogic::AddGuildMember(const guild_id_type guild_id,
                                       const role_uuid_type role_uuid,
                                       error_code& ec) {
  if (role_uuid == kInvalidRoleUuid) {
    ec = ErrorCode::ERR_INVALID_ROLE_UUID;
    return false;
  }

  if (guild_id == kInvalidGuildId) {
    ec = ErrorCode::ERR_INVALID_GUILD_ID;
    return false;
  }

  if (GuildServiceBasicSingleton->HasGuild(role_uuid)) {
    ec = ErrorCode::ERR_GUILD_ALREADY_EXIST;
    return false;
  }

  // const Guild* guild_ptr = GuildServiceBasicSingleton->GetGuild(guild_id);
  // if (guild_ptr == nullptr) {
  //   ec = ErrorCode::ERR_GUILD_NOT_EXIST;
  //   // LOG_WARN("非法公会 公会id:%llu", guild_id);
  //   return false;
  // }

  // if (!GuildServiceBasicSingleton->AddGuildRole(guild_ptr->id, role_uuid)) {
  //   ec = ErrorCode::ERR_GUILD_MEMBERS_ADD_FAILED;
  //   // LOG_WARN("添加公会角色失败 角色唯一id:%llu 公会唯一id:%llu", role_uuid,
  //   // guild_id);
  //   return false;
  // }

  GuildModuleMembers module_members;
  if (!GuildMembersLogic::GetModuleMembers(guild_id, module_members)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_LOAD_FAILED;
    return false;
  }

  if (module_members.members.size() >= kMaxGuildMemberSize) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_FULL;
    return false;
  }

  {
    GuildMember guild_member;
    guild_member.role_uuid = role_uuid;
    guild_member.name = std::to_string(role_uuid);
    guild_member.duty = guildservicebasic_cpp::GuildDuty::GUILD_DUTY_COMMON;

    module_members.members.emplace_back(guild_member);

    if (!detail::SaveGuildModule<GuildModuleMembers>(kGuildServiceBasicName,
                                               module_members, guild_id,
                                               kGuildModuleMembersName)) {
      ec = ErrorCode::ERR_GUILD_MEMBERS_SAVE_FAILED;
      // LOG_WARN("保存公会角色失败 角色唯一id:%llu 公会:%s", role_uuid,
      // DumpGuild(*guild_ptr).c_str());
      return false;
    }
  }

  if (!GuildServiceBasic::SaveGuildRoleToRedis(kRedisSetOp, role_uuid,
                                               guild_id)) {
    ec = ErrorCode::ERR_GUILD_MEMBERS_ADD_ID_FAILED;
    // LOG_WARN("保存角色查询公会id失败 角色唯一id:%llu 公会:%s", role_uuid,
    // DumpGuild(*guild_ptr).c_str());
    return false;
  }

  return true;
}

}  // namespace guild_service